package net.wanderinghorse.jsonmessage;

import java.io.Serializable;
import java.util.Map;
import java.util.HashMap;
/**
 * A simple string-to-string aliasing utility.
 */
public class Aliaser implements Serializable {
    private final Map<String,String> map = new HashMap<String,String>();

    private int maxRedirects = 10;

    /**
     * Empty-initializes this object.
     */
    public Aliaser()
    {
    }

    /**
     * Adds alias as an alias for expandsTo.
     * @param alias The alias form of the string.
     * @param expandsTo The "full" form of the string.
     */
    public void alias( final String alias, final String expandsTo )
    {
        synchronized (this.map) {
            this.map.put( alias, expandsTo );
        }
    }

    /**
     * Tries to resolve a mapped alias.
     * @param key The alias to expand.
     * @return The expanded string, or null if key is not mapped as an alias.
     * @throws RuntimeException if alias expansion appears to be cyclic (too
     * many levels of redirection/expansion). As a special case, an alias which
     * expands directly to itself (with no intermediate expansions) will be returned
     * as-is.
     */
    public String resolve( String key )
    {
        int level = 0;
        String got = null;
        synchronized (this.map) {
            for( ; level < this.maxRedirects; ++level )
            {
                got = this.map.get(key);
                if( null == got ) break;
                else if( got.equals(key) ) break;
                else if( this.map.containsKey(got)) {
                    key = got;
                    continue;
                }
                else break;
            }
        }
        if( level >= this.maxRedirects ) {
            throw new RuntimeException("Too many levels of alias expansion, possibly caused by cyclic aliases! "+
                    "Check alias mappings for ["+got+"]!");
        }
        return got;
    }

    /**
     * @return The maximum number of redirects/expansions to handle in resolve().
     */
    public int getMaxRedirects() {
        return maxRedirects;
    }

    /**
     * @param maxRedirects Maximum expansion level to support in resolve().
     * @throws IllegalArgumentException If maxRedirects is <=0.
     */
    public void setMaxRedirects(int maxRedirects) {
        if( maxRedirects <= 0 ) {
            throw new IllegalArgumentException("Aliaser.setMaxRedirects(VAL) must be >0!");
        }
        this.maxRedirects = maxRedirects;
    }
}
